﻿/* PN264 - A Parallel H.264 Encoding Utility
 * Copyright © 2009 PN264 Development Team
 *
 * This software is released the terms and conditions of the MIT License,
 * a copy of which can be found in the License.txt file.
 *
 * Contributors:
 * Will 'AnarkiNet' Shelley (AnarkiNet@gmail.com)
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using Npgsql;
using System.IO;
using PN264.Resources;

namespace PN264
{
    /// <summary>
    /// Provides a thin abstraction layer that enables access to the PN264
    /// database file.
    /// </summary>
    public sealed class Database : IDisposable
    {
        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="Database"/> class.
        /// </summary>
        /// <param name="path">The path of the database file.</param>
        public Database()
        {
            NpgsqlConnectionStringBuilder sb = new NpgsqlConnectionStringBuilder();
            sb.Host = "192.168.255.253";
            sb.UserName = "postgres";
            sb.Password = "postgres";


            this.connection = new NpgsqlConnection(sb.ConnectionString);

            this.commitCommand = new NpgsqlCommand("COMMIT;", this.connection);

            this.createJobCommand = new NpgsqlCommand(SqlCommands.CreateJob, this.connection);
            this.createProfileCommand = new NpgsqlCommand(SqlCommands.CreateProfile, this.connection);
            this.createTaskCommand = new NpgsqlCommand(SqlCommands.CreateTask, this.connection);

            this.listJobs = new NpgsqlCommand(SqlCommands.ListJobs, this.connection);
            this.listProfiles = new NpgsqlCommand(SqlCommands.ListProfiles, this.connection);
            this.listTasks = new NpgsqlCommand(SqlCommands.ListTasks, this.connection);

            this.loadJob = new NpgsqlCommand(SqlCommands.LoadJob, this.connection);
            this.loadJob.Parameters.Add(new NpgsqlParameter("@JobId", DbType.Int64));

            this.loadTask = new NpgsqlCommand(SqlCommands.LoadTask, this.connection);
            this.loadTask.Parameters.Add(new NpgsqlParameter("@JobId", DbType.Int64));

            this.saveJob = new NpgsqlCommand(SqlCommands.SaveJob, this.connection);
            
            this.saveTask = new NpgsqlCommand(SqlCommands.SaveTask, this.connection);
        }
        /// <summary>
        /// Finalizes the current <see cref="Database"/>.
        /// </summary>
        ~Database()
        {
            this.Dispose(false);
        }
        #endregion
        #region Fields
        private readonly NpgsqlCommand commitCommand;
        private readonly NpgsqlConnection connection;
        private readonly NpgsqlCommand createJobCommand;
        private readonly NpgsqlCommand createProfileCommand;
        private readonly NpgsqlCommand createTaskCommand;
        private bool isDisposed;
        private readonly NpgsqlCommand listJobs;
        private readonly NpgsqlCommand listProfiles;
        private readonly NpgsqlCommand listTasks;
        private readonly NpgsqlCommand loadJob;
        private readonly NpgsqlCommand loadTask;
        private readonly NpgsqlCommand saveJob;
        private readonly NpgsqlCommand 
        private readonly NpgsqlCommand saveTask;
        #endregion
        #region Methods
        /// <summary>
        /// Closes the current <see cref="Database"/>.
        /// </summary>
        public void Close()
        {
            if (this.IsDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }
            this.connection.Close();
        }
        /// <summary>
        /// Disposes the current <see cref="Database"/>.
        /// </summary>
        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }
        /// <summary>
        /// Disposes any unmanaged resources used by the current
        /// <see cref="Database"/>.
        /// </summary>
        /// <param name="disposing">Determines whether managed resources are
        /// disposed in addition to unmanaged resources.</param>
        private void Dispose(bool disposing)
        {
            if (!this.IsDisposed)
            {
                if (disposing)
                {
                    this.connection.Dispose();
                    this.listJobs.Dispose();
                    this.listProfiles.Dispose();
                    this.listTasks.Dispose();
                    this.loadJob.Dispose();
                    this.loadTask.Dispose();
                    this.saveJob.Dispose();
                }
                this.isDisposed = true;
            }
        }

        /// <summary>
        /// Ensures that the underlying data store is initialized.
        /// </summary>
        public void Initialize()
        {
            if (this.connection.State != ConnectionState.Open)
            {
                this.Open();

                var cmd = new NpgsqlCommand(SqlCommands.InitializeDB, this.connection);

                cmd.ExecuteNonQuery();
            }
        }

        /// <summary>
        /// Creates a new <see cref="Job"/> with the next available id from the
        /// database.
        /// </summary>
        /// <returns></returns>
        public Job CreateJob()
        {
            if (this.IsDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }
            return new Job((long)this.createJobCommand.ExecuteScalar());
        }
        /// <summary>
        /// Creats a new <see cref="Profile"/> with the next available id from
        /// the database.
        /// </summary>
        /// <returns></returns>
        public Profile CreateProfile()
        {
            if (this.IsDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }
            return new Profile((long)this.createProfileCommand.ExecuteScalar());
        }
        /// <summary>
        /// Creates a new <see cref="Task"/> with the next available id from
        /// the database.
        /// </summary>
        /// <returns></returns>
        public Task CreateTask()
        {
            if (this.IsDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }
            return new Task((long)this.createTaskCommand.ExecuteScalar());
        }
        /// <summary>
        /// Overridden. Retrieves a list of all <see cref="Job"/>s in the
        /// database.
        /// </summary>
        /// <returns></returns>
        public IEnumerable<long> ListJobs()
        {
            if (this.IsDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }
            var reader = this.listJobs.ExecuteReader();

            while (reader.Read())
            {
                yield return (long)reader["Id"];
            }
        }
        /// <summary>
        /// Overridden. Retrieves a list of all <see cref="Profile"/>s in the
        /// database.
        /// </summary>
        /// <returns></returns>
        public IEnumerable<long> ListProfiles()
        {
            if (this.IsDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }
            throw new NotImplementedException();
        }
        /// <summary>
        /// Overridden. Retrieves a list of all <see cref="Task"/>s in the
        /// database.
        /// </summary>
        /// <returns></returns>
        public IEnumerable<long> ListTasks()
        {
            if (this.IsDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }
            throw new NotImplementedException();
        }
        /// <summary>
        /// Overridden. Retrieves the <see cref="Job"/> with the specified id
        /// from the database.
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Job LoadJob(long id)
        {
            if (this.IsDisposed)
                throw new ObjectDisposedException(this.GetType().Name);
            
            throw new NotImplementedException();
        }
        /// <summary>
        /// Overridden. Retrieves the <see cref="Profile"/> with the specified
        /// id from the database.
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Profile LoadProfile(long id)
        {
            if (this.IsDisposed)
                throw new ObjectDisposedException(this.GetType().Name);
            
            throw new NotImplementedException();
        }
        /// <summary>
        /// Overridden. Retrieves the <see cref="Task"/> with the specified id
        /// from the database.
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Task LoadTask(long id)
        {
            if (this.IsDisposed)
                throw new ObjectDisposedException(this.GetType().Name);
            
            throw new NotImplementedException();
        }
        /// <summary>
        /// Overridden. Stores the specified <see cref="Job"/> to the database.
        /// </summary>
        /// <param name="job"></param>
        public void SaveJob(Job job)
        {
            if (this.IsDisposed)
                throw new ObjectDisposedException(this.GetType().Name);
            
            throw new NotImplementedException();
        }
        /// <summary>
        /// Overridden. Stores the specified <see cref="Profile"/> to the
        /// database.
        /// </summary>
        /// <param name="profile"></param>
        public void SaveProfile(Profile profile)
        {
            if (this.IsDisposed)
                throw new ObjectDisposedException(this.GetType().Name);
            
            throw new NotImplementedException();
        }
        /// <summary>
        /// Overridden. Stores the specified <see cref="Task"/> to the
        /// database.
        /// </summary>
        /// <param name="task"></param>
        public void SaveTask(Task task)
        {
            if (this.IsDisposed)
                throw new ObjectDisposedException(this.GetType().Name);
            
            throw new NotImplementedException();
        }
        /// <summary>
        /// Opens the current <see cref="Database"/>.
        /// </summary>
        public void Open()
        {
            if (this.IsDisposed)
                throw new ObjectDisposedException(this.GetType().Name);
            
            this.connection.Open();
        }
        #endregion
        #region Properties
        /// <summary>
        /// Gets a value that indicates if the current <see cref="Database"/>
        /// has been disposed.
        /// </summary>
        public bool IsDisposed
        {
            get
            {
                return this.isDisposed;
            }
        }
        #endregion
    }
}
